manage.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. //管理js文件 获取modeldata.js 判断是否有特殊的字段,如果有就先加载SpecialScene.js 里面有对特殊场景处理的代码 否则就直接加载main
  2. var Manage = function(){
  3. this.weixinURL = "https://res.wx.qq.com/open/js/jweixin-1.2.0.js",
  4. this.time = "?"+new Date().getTime();
  5. this.loadAudio();
  6. this.loadWeixin();
  7. }
  8. //动态加载js文件
  9. Manage.prototype.LoadJs = function(_files, succes){
  10. /* 已加载文件缓存列表,用于判断文件是否已加载过,若已加载则不再次加载*/
  11. var classcodes = [];
  12. var FileArray = [];
  13. if (typeof _files === "object") {
  14. FileArray = _files;
  15. } else {
  16. /*如果文件列表是字符串,则用,切分成数组*/
  17. if (typeof _files === "string") {
  18. FileArray = _files.split(",");
  19. }
  20. }
  21. if (FileArray != null && FileArray.length > 0) {
  22. var LoadedCount = 0;
  23. for (var i = 0; i < FileArray.length; i++) {
  24. loadFile(FileArray[i], function() {
  25. LoadedCount++;
  26. if (LoadedCount == FileArray.length) {
  27. try {
  28. succes();
  29. }
  30. catch(err) {
  31. console.log("err: 您未定义回调");
  32. }
  33. }
  34. })
  35. }
  36. }
  37. /*加载JS文件,url:文件路径,success:加载成功回调函数*/
  38. function loadFile(url, success) {
  39. if (!FileIsExt(classcodes, url)) {
  40. var _ThisType = GetFileType(url);
  41. var ThisType = _ThisType.indexOf("?") == -1 ? _ThisType : _ThisType.substring(0,_ThisType.indexOf("?"));
  42. var fileObj = null;
  43. if (ThisType == ".js") {
  44. fileObj = document.createElement('script');
  45. fileObj.src = url;
  46. } else if (ThisType == ".css") {
  47. fileObj = document.createElement('link');
  48. fileObj.href = url;
  49. fileObj.type = "text/css";
  50. fileObj.rel = "stylesheet";
  51. } else if (ThisType == ".less") {
  52. fileObj = document.createElement('link');
  53. fileObj.href = url;
  54. fileObj.type = "text/css";
  55. fileObj.rel = "stylesheet/less";
  56. }
  57. success = success || function() {};
  58. fileObj.onload = fileObj.onreadystatechange = function() {
  59. if (!this.readyState || 'loaded' === this.readyState || 'complete' === this.readyState) {
  60. success();
  61. classcodes.push(url)
  62. }
  63. }
  64. document.getElementsByTagName('head')[0].appendChild(fileObj);
  65. } else {
  66. success();
  67. }
  68. }
  69. /*获取文件类型,后缀名,小写*/
  70. function GetFileType(url) {
  71. if (url != null && url.length > 0) {
  72. return url.substr(url.lastIndexOf(".")).toLowerCase();
  73. }
  74. return "";
  75. }
  76. /*文件是否已加载*/
  77. function FileIsExt(FileArray, _url) {
  78. if (FileArray != null && FileArray.length > 0) {
  79. var len = FileArray.length;
  80. for (var i = 0; i < len; i++) {
  81. if (FileArray[i] == _url) {
  82. return true;
  83. }
  84. }
  85. }
  86. return false;
  87. }
  88. };
  89. //获取页面url后面的参数
  90. Manage.prototype.number = function(variable) {
  91. var query = window.location.search.substring(1);
  92. var vars = query.split("&");
  93. for (var i=0;i<vars.length;i++) {
  94. var pair = vars[i].split("=");
  95. if(pair[0] == variable){return pair[1];}
  96. }
  97. return(false);
  98. };
  99. Manage.prototype.loadWeixin = function() {
  100. var that = this;
  101. this.LoadJs(that.weixinURL+that.time,function(){ });
  102. }
  103. Manage.prototype.loadAudio = function() { //相关:g_tourAudio \ g_playAudio
  104. g_bgAudio = new Audio;
  105. g_bgAudio.loop = true;
  106. g_bgAudio.autoplay = true;
  107. g_bgAudio.id = "bgaudio";
  108. //https://www.cnblogs.com/interdrp/p/4211883.html 部分资料
  109. g_bgAudio.load(); // iOS 9 还需要额外的 load 一下, 否则直接 play 无效
  110. var play = function(){
  111. //if(window.tourAudioSta) return;
  112. if(this.bgmShouldPlay){
  113. this.switchBgmState(true)
  114. }
  115. document.removeEventListener("touchstart",play);
  116. document.removeEventListener("click",play);
  117. $('#player')[0].removeEventListener("touchstart", play);
  118. }.bind(this);
  119. g_bgAudio.oncanplay = ()=>{
  120. this.switchBgmState(true)
  121. }
  122. document.addEventListener("WeixinJSBridgeReady", ()=> {
  123. this.switchBgmState(true)
  124. }, false);
  125. document.addEventListener("touchstart", play);//ios需要加个事件才能播放 不能自动播放;如果还有浏览器不行,换成别的交互事件
  126. document.addEventListener("click", play);
  127. $('#player')[0].addEventListener("touchstart", play);
  128. g_bgAudio.addEventListener('ended', ()=>{
  129. this.switchBgmState(true)
  130. });
  131. $("#volume").find("a").on("click", ()=> {
  132. if($("#volume img")[0].src.indexOf("btn_on.png")>-1)
  133. {
  134. this.switchBgmState(true);
  135. }
  136. else if($("#volume img")[0].src.indexOf("btn_off.png")>-1)
  137. {
  138. this.switchBgmState(false);
  139. }
  140. })
  141. }
  142. Manage.prototype.switchBgmState = function(state){
  143. if(!g_bgAudio || !g_bgAudio.src) return;
  144. this.bgmShouldPlay = state
  145. var played = function(){
  146. console.log('begin play bgm');
  147. g_play = 1;
  148. g_playAudio = g_bgAudio;
  149. $("#volume a img").attr("src", "./images/Volume btn_off.png")
  150. $("#volume").attr("title", "关闭声音");
  151. g_tourAudio && g_tourAudio.pause()
  152. }
  153. var paused = function(){
  154. g_play = 0;
  155. g_playAudio == g_bgAudio && (g_playAudio = null)
  156. $("#volume a img").attr("src", "./images/Volume btn_on.png")
  157. $("#volume").attr("title", "打开声音");
  158. }
  159. if(state ){
  160. g_bgAudio.play();
  161. if(g_bgAudio.paused){
  162. paused()
  163. }else{
  164. played()
  165. return true
  166. }
  167. }else{
  168. g_bgAudio.pause();
  169. paused()
  170. }
  171. g_bgAudio.pauseByHot = false
  172. g_bgAudio.pauseByTour = false
  173. }
  174. Manage.prototype.weixinShare = function() {
  175. console.log("weixinShare")
  176. $.ajax({
  177. url:'https://www.4dage.com/wechat/jssdk/',
  178. type: "post",
  179. data : {
  180. 'url' : location.href.split('#')[0]
  181. },
  182. dataType:"jsonp",
  183. jsonpCallback:"success_jsonp",
  184. success:function(data,textStatus){
  185. console.log("weixinShare success")
  186. console.log(data.appId)
  187. wx.config({
  188. // debug : true,
  189. appId : data.appId,
  190. timestamp : data.timestamp,
  191. nonceStr : data.nonceStr,
  192. signature : data.signature,
  193. jsApiList : [ 'checkJsApi', 'onMenuShareTimeline',
  194. 'onMenuShareAppMessage', 'onMenuShareQQ',
  195. 'onMenuShareWeibo', 'hideMenuItems',
  196. 'showMenuItems', 'hideAllNonBaseMenuItem',
  197. 'showAllNonBaseMenuItem', 'translateVoice',
  198. 'startRecord', 'stopRecord', 'onRecordEnd',
  199. 'playVoice', 'pauseVoice', 'stopVoice',
  200. 'uploadVoice', 'downloadVoice', 'chooseImage',
  201. 'previewImage', 'uploadImage', 'downloadImage',
  202. 'getNetworkType', 'openLocation', 'getLocation',
  203. 'hideOptionMenu', 'showOptionMenu', 'closeWindow',
  204. 'scanQRCode', 'chooseWXPay',
  205. 'openProductSpecificView', 'addCard', 'chooseCard',
  206. 'openCard' ]
  207. });
  208. },
  209. error:function(XMLHttpRequest,textStatus,errorThrown){
  210. console.log("jsonp.error:"+textStatus);
  211. }
  212. });
  213. var success_jsonp = function(json){
  214. console.log(json);
  215. };
  216. wx.ready(function(){
  217. // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行〿
  218. //对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中〿
  219. //分享到朋友圈
  220. console.log(g_weixinObj)
  221. wx.onMenuShareTimeline({
  222. title: g_weixinObj.title, // 分享标题
  223. link: g_weixinObj.lineLink, // 分享链接
  224. imgUrl: g_weixinObj.imgUrl, // 分享图标
  225. desc: g_weixinObj.desc
  226. });
  227. //获取“分享给朋友”按钮点击状态及自定义分享内容接叿
  228. wx.onMenuShareAppMessage({
  229. title: g_weixinObj.title, // 分享标题
  230. desc: g_weixinObj.desc, // 分享描述
  231. link: g_weixinObj.lineLink, // 分享链接
  232. imgUrl: g_weixinObj.imgUrl, // 分享图标
  233. type: '', // 分享类型,music、video或link,不填默认为link
  234. dataUrl: '' // 如果type是music或video,则要提供数据链接,默认为空
  235. });
  236. wx.onMenuShareWeibo({
  237. title: g_weixinObj.title, // 分享标题
  238. desc: g_weixinObj.desc, // 分享描述
  239. link: g_weixinObj.lineLink, // 分享链接
  240. imgUrl: g_weixinObj.imgUrl, // 分享图标
  241. success: function () {
  242. // 用户确认分享后执行的回调函数
  243. },
  244. cancel: function () {
  245. // 用户取消分享后执行的回调函数
  246. }
  247. });
  248. wx.onMenuShareQZone({
  249. title: g_weixinObj.title, // 分享标题
  250. desc: g_weixinObj.desc, // 分享描述
  251. link: g_weixinObj.lineLink, // 分享链接
  252. imgUrl: g_weixinObj.imgUrl, // 分享图标
  253. success: function () {
  254. // 用户确认分享后执行的回调函数
  255. },
  256. cancel: function () {
  257. // 用户取消分享后执行的回调函数
  258. }
  259. });
  260. wx.onMenuShareQQ({
  261. title: g_weixinObj.title, // 分享标题
  262. desc: g_weixinObj.desc, // 分享描述
  263. link: g_weixinObj.lineLink, // 分享链接
  264. imgUrl: g_weixinObj.imgUrl, // 分享图标
  265. success: function () {
  266. // 用户确认分享后执行的回调函数
  267. },
  268. cancel: function () {
  269. // 用户取消分享后执行的回调函数
  270. }
  271. });
  272. wx.error(function(res){
  273. // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名〿
  274. });
  275. });
  276. }
  277. Manage.prototype.dealURL = function(src, type){
  278. //music: "///super.4dage.com/data/LYW/edit/20200928_151633415.mp3"
  279. //"https://super.4dage.com/data/LYW/edit/20200928_165319399.jpg"]
  280. if(window.isLocal && settings.localPrefix!=void 0){//本地将线上的前缀替换
  281. var oldPrefixs = ["https://super.4dage.com/", "http://super.4dage.com/", "///super.4dage.com/"]
  282. for(let i=0;i<oldPrefixs.length;i++){
  283. if(src.includes(oldPrefixs[i])){
  284. return src.replace(oldPrefixs[i], settings.localPrefix)
  285. break;
  286. }
  287. }
  288. console.error("没有找到合适的本地链接")
  289. return src
  290. }else{
  291. //add https://
  292. var prefix = g_Prefix.replace('https://','').replace('http://','')
  293. if(!src.includes('http:/') && !src.includes('https:/') && src.includes(prefix)){
  294. src = 'https://'+src
  295. }
  296. return src
  297. }
  298. }
  299. Manage.prototype.removeSrcPostMark = function(url){//去除texture.load时自动加上的'?'
  300. var index = url.indexOf('?')
  301. if(index>-1){
  302. return url.slice(0, index)
  303. }else return url
  304. }
  305. Manage.prototype.showInfo = function (o) { // ({result:true, title:"发布成功"});
  306. var box = $(".resultBox");
  307. var title = o.title || o || i18n.get('保存成功');
  308. box.children().eq(0).html(title)
  309. //var time = o.time || THREE.Math.clamp((Config.lang=='en') ? title.length*50 : title.length*130 ,1300,5000);
  310. var time = o.time || THREE.Math.clamp(title.length*130 ,1300, 5000);
  311. o.time || console.log("showtime " + time)
  312. //实际有一半的时间在渐变透明度
  313. this.showInfoTimer && clearTimeout(this.showInfoTimer)
  314. box.removeClass("animate");//如果之后不久又要showinfo一个的话,先停止前面的animate
  315. setTimeout(function () {
  316. box.css(
  317. {
  318. '-webkit-animation-duration': time + 'ms',
  319. 'animation-duration': time + 'ms'
  320. }
  321. )
  322. if(o.top){
  323. box.children().css('top', o.top + "%");
  324. }else{
  325. box.children().css('top', '' )
  326. }
  327. box.removeClass("hide");
  328. box.addClass("animate");
  329. if (o.dontInteract) {//遮挡对屏幕的操作
  330. box.css('pointer-events', 'auto')
  331. } else {
  332. box.css('pointer-events', 'none')
  333. }
  334. this.showInfoTimer = setTimeout(function () {
  335. box.removeClass("animate");
  336. box.addClass("hide");
  337. this.showInfoTimer = null;
  338. }.bind(this), time + 20)
  339. }.bind(this), 50)//这个数字太小的话后面触发的没有重新animate的效果 应该要比帧率大吧
  340. }//like: manage.showInfo({title:'a', top:20})
  341. var manage = new Manage();
  342. //公用的函数
  343. function getQueryVariable(variable)
  344. {
  345. var query = window.location.search.substring(1);
  346. var vars = query.split("&");
  347. for (var i=0;i<vars.length;i++) {
  348. var pair = vars[i].split("=");
  349. if(pair[0] == variable){return pair[1];}
  350. }
  351. return(false);
  352. }
  353. //隐藏公司Logo
  354. function showLogo(){
  355. $("#myCompany").hide();
  356. $("#loaderCoBrandName").hide();
  357. $("#title-logo").hide();
  358. $(".title-container").css("justify-content","center")
  359. }
  360. //czj 添加随机的时间
  361. function randomTime(){
  362. return new Date()
  363. };
  364. function matcher(data){
  365. if(!data || !g_version ) return data;
  366. delete data.model.vision_version;
  367. var _data = {
  368. files: {
  369. "templates": ["images/images{{number}}/{{filename}}"]
  370. },
  371. model :{
  372. sid :window.number,
  373. camera_start:
  374. data.model.images && data.model.images.length != 0 ?
  375. {
  376. camera: {
  377. zoom: "-1",
  378. quaternion: [
  379. JSON.parse(data.model.images[0].metadata).camera_quaternion.z,
  380. JSON.parse(data.model.images[0].metadata).camera_quaternion.w,
  381. JSON.parse(data.model.images[0].metadata).camera_quaternion.x,
  382. JSON.parse(data.model.images[0].metadata).camera_quaternion.y
  383. ]
  384. },
  385. pano: { uuid: JSON.parse(data.model.images[0].metadata).scan_id },
  386. mode: "0"
  387. }
  388. : ''
  389. },
  390. sid: window.number,
  391. hoticon: {
  392. default: "https://super.4dage.com/images/4dagePoint2.png",
  393. higt: "https://super.4dage.com/images/4dagePoint.png"
  394. },
  395. special: "false",
  396. weixinDesc: ""
  397. };
  398. $.extend(true,data,_data)
  399. return data;
  400. }
  401. function hotMatcher(data={}){
  402. //if(!data || !g_version) return data;
  403. if(g_version) {
  404. data.tourAudio = data.audio || {};
  405. }else{
  406. data.tourAudio = {}
  407. }
  408. return data;
  409. }
  410. var GifTexDeal = {
  411. animateObjects : [],
  412. animateTexs : [] ,
  413. addAnimation : function(texture, owner, info, id){
  414. /* if(this.animateObjects.find(e=>
  415. e.texture == texture && !ifSame(info, e.info)
  416. )) */
  417. var animation
  418. var tex = this.animateTexs.find(e=>e.texture == texture)
  419. if(tex){
  420. animation = tex
  421. }else{
  422. animation = {texture,info }
  423. this.animateTexs.push(animation)
  424. this.setRepeart(animation)
  425. }
  426. var object = {
  427. animation, //默认相同的texture对应的info是一样的, 对应一个animation
  428. owner,
  429. }
  430. this.animateObjects.push(object)
  431. return object
  432. },
  433. remove : function(object){
  434. var index = this.animateObjects.indexOf(object)
  435. if(index>-1){
  436. if(!this.animateObjects.find(e=>e.animation == object.animation)){
  437. let i = this.animateTexs.indexOf(object.animation)
  438. this.animateTexs.splice(i, 1)
  439. object.animation.texture.repeat.set(1,1)
  440. }
  441. this.stop(object)
  442. this.animateObjects.splice(index, 1)
  443. }
  444. },
  445. setRepeart : function(animation){
  446. animation.texture.repeat.set(1/animation.info.cellXcount, 1/animation.info.cellYcount)
  447. },
  448. start: function(object){
  449. if(!object || object.started )return;
  450. object.started = true
  451. if(object.animation.started)return;
  452. object.animation.started = true
  453. var info = object.animation.info
  454. var count = info.cellXcount * info.cellYcount - (info.voidCount || 0)
  455. if(count <= 1)return;
  456. transitions.start( (progress)=>{
  457. var index = Math.floor(count * progress);
  458. var indexX = index % info.cellXcount
  459. var indexY = info.cellYcount - Math.floor(index /info.cellXcount ) - 1; //uv.offset.y是从下到上的
  460. object.animation.texture.offset.x = indexX / info.cellXcount;
  461. object.animation.texture.offset.y = indexY / info.cellYcount;
  462. //console.log(object.id + " : "+ object.texture.offset.toArray())
  463. } , info.duration * (-1), null,/* ()=>{//done (-1):循环
  464. object.started = false
  465. object.texture.offset.x = 0;
  466. object.texture.offset.y = 0;
  467. this.start(object)
  468. }, */ 0 ,null, object.id, "gif_"+object.animation.texture.id);
  469. },
  470. stop: function(object){
  471. if(!object || !object.started)return;
  472. object.started = false
  473. //只有该object对应的texture对应的所有object都停止了,才能真的停止动画:
  474. if(this.animateObjects.find(e=>e.animation == object.animation && e.started)) return;
  475. transitions.cancelById("gif_"+object.animation.texture.id);
  476. object.animation.texture.offset.set(0,0)
  477. object.animation.started = false
  478. }
  479. }
  480. var CloneObject = function(copyObj, result, isSimpleCopy, extraReplace) {
  481. //isSimpleCopy只复制最外层
  482. //复制json result的可能:普通数字或字符串、普通数组、复杂对象
  483. if(!copyObj)return copyObj //0 null undefined ''
  484. result = result || {};
  485. if (copyObj instanceof Array) {
  486. /* if (copyObj[0]instanceof Object) {
  487. //不支持含有 [[Object]] 这样二级数组里面还是复杂数据的,普通和复杂的数据混合可能也不支持
  488. console.error("不支持含有 [[Object]] 这样二级数组里面还是复杂数据的...")
  489. }
  490. return copyObj.slice(0);*/ //如果是数组,直接复制返回(排除数组内是object
  491. return copyObj.map(e=>{
  492. if(e instanceof Object){
  493. return CloneObject(e)
  494. }else return e
  495. })
  496. }else{
  497. if(copyObj.clone instanceof Function ){ //解决一部分
  498. return copyObj.clone()
  499. }
  500. }
  501. for (var key in copyObj) {
  502. if (copyObj[key] instanceof Object && !isSimpleCopy)
  503. result[key] = CloneObject(copyObj[key]);
  504. else
  505. result[key] = copyObj[key];
  506. //如果是函数类同基本数据,即复制引用
  507. }
  508. return result;
  509. }
  510. ;
  511. var ifSame = function(object1, object2){
  512. if(object1 == object2 )return true // 0 != undefined , 0 == ''
  513. else if(!object1 || !object2) return false
  514. else if(object1.constructor != object2.constructor){
  515. return false
  516. }else if(object1 instanceof Array ) {
  517. if(object1.length != object2.length)return false;
  518. var _object2 = object2.slice(0);
  519. for(let i=0;i<object1.length;i++){
  520. var u = _object2.find(e=>ifSame(object1[i], e));
  521. if(u == void 0 && !_object2.includes(u) && !object1.includes(u))return false;
  522. else{
  523. let index = _object2.indexOf(u);
  524. _object2.splice(index,1);
  525. }
  526. }
  527. return true
  528. }else if(object1.equals instanceof Function ){//复杂数据仅支持这种,其他的可能卡住?
  529. return object1.equals(object2)
  530. }else if(typeof object1 == 'number' || typeof object1 == 'string'){
  531. if(isNaN(object1) && isNaN(object2))return true
  532. else return object1 == object2
  533. }else if(typeof object1 == "object"){
  534. var keys1 = Object.keys(object1)
  535. var keys2 = Object.keys(object2)
  536. if(!ifSame(keys1,keys2))return false;
  537. for(let i in object1){
  538. var same = ifSame(object1[i], object2[i]);
  539. if(!same)return false
  540. }
  541. return true
  542. }else{
  543. console.log('isSame出现例外')
  544. }
  545. }
  546. var SoundPriority = {//暂不支持同时播放
  547. currentPlay:null,//当前正在播放list中的哪一个
  548. list:[
  549. {
  550. name:"bg",
  551. level : 0,//越大优先级越高
  552. canBeInterrupted : true ,
  553. },
  554. {
  555. name:"boxVideo",
  556. level : 1,
  557. canBeInterrupted : true,
  558. checkIfNeedPlay:function(){
  559. }
  560. },
  561. {
  562. name:"hot",
  563. level : 2,
  564. canBeInterrupted : true
  565. },
  566. {
  567. name:"tour",
  568. level : 3,
  569. canBeInterrupted : true
  570. },
  571. ],
  572. register:function(){
  573. }
  574. }
  575. //兼容一代的場景
  576. //請求地址統一管理
  577. var g_onePregix = "https://bigscene.4dage.com/" //对应一代 http://www.4dmodel.com/SuperPanoramic/index.html?m=55
  578. var g_version = manage.number("version");
  579. g_version === "one" ? g_Prefix = g_onePregix : '';